﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace Be.Windows.Forms
{
    public static class UnixHelper
    {
        public static bool IsUnix
        {
            get
            {
                var platform = Environment.OSVersion.Platform;
                return platform == PlatformID.Unix || platform == PlatformID.MacOSX;
            }
        }

        public static void CreateCaret(Control control, int width, int height)
        {
            if (caret != null)
            {
                caret.Dispose();
            }
            caret = new Caret(control, new Size(width, height));
        }

        public static void ShowCaret(Control control)
        {
            if (caret != null && caret.Control == control)
            {
                caret.Show();
            }
        }

        public static void DestroyCaret()
        {
            if (caret != null)
            {
                caret.Dispose();
                caret = null;
            }
        }

        public static void SetCaretPos(int x, int y)
        {
            if (caret != null)
            {
                caret.Position = new Point(x, y);
            }
        }

        private static Caret caret;

        private class Caret : IDisposable
        {
            public Caret(Control control, Size size)
            {
                this.Size = size;
                
                this.Control = control;
                control.Disposed += control_Disposed;
                control.Paint += control_Paint;

                timer = new Timer();
                timer.Interval = SystemInformation.CaretBlinkTime;
                timer.Tick += timer_Tick;
                timer.Start();
            }

            void timer_Tick(object sender, EventArgs e)
            {
                visible = !visible;
                Control.Invalidate();
            }

            void control_Paint(object sender, PaintEventArgs e)
            {
                if (IsVisible)
                {
                    e.Graphics.FillRectangle(Brushes.Black,
                        new Rectangle(position, Size));
                }
            }

            void control_Disposed(object sender, EventArgs e)
            {
                Dispose();
            }
            
            public Control Control
            {
                get;
                private set;
            }
            
            public Point Position
            {
                get
                {
                    return position;
                }
                set
                {
                    if (position != value)
                    {
                        Control.Invalidate();
                        position = value;
                    }
                }
            }

            public Size Size
            {
                get;
                private set;
            }

            public void Show()
            {
                visible = true;
                if (visibility == 0)
                {
                    return;
                }
                visibility--;
                if (visibility == 0)
                {
                    Control.Invalidate();
                }
            }

            public void Hide()
            {
                visibility++;
                if (visibility == 1)
                {
                    Control.Invalidate();
                }
            }

            private Point position;

            private bool IsVisible
            {
                get
                {
                    return visible && visibility == 0;
                }
            }

            private int visibility = 1;

            private bool visible;

            private readonly Timer timer;

            #region Implementation of IDisposable

            /// <summary>
            /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
            /// </summary>
            /// <filterpriority>2</filterpriority>
            public void Dispose()
            {
                Control.Disposed -= control_Disposed;
                Control.Paint -= control_Paint;
                timer.Dispose();
            }

            #endregion
        }
    }
}
